
#include <BRender>
#include <BOpenGL>
#include <BDisplay>
#include <BButton>
#include "member_BWidget.h"
#include "member_BDisplay.h"
#include "member_BTexture.h"
#include "IWindow.h"

using namespace BWE;

#define member					(*(member_BDisplay*)_ptr)
#define member_allocate()		_ptr = new member_BDisplay(this)
#define member_release()		delete (member_BDisplay*)_ptr

BDisplay::BDisplay()
{
	member_allocate();
}
BDisplay::BDisplay(int width, int height)
{
	member_allocate();
	setSize(BSize(width, height));
}
BDisplay::~BDisplay()
{
	member_release();
}

void BDisplay::setWidth(int width)
{
	member.size.setWidth(width);
}
int BDisplay::width() const
{
	return member.size.width();
}

void BDisplay::setHeight(int height)
{
	member.size.setHeight(height);
}
int BDisplay::height() const
{
	return member.size.height();
}

void BDisplay::setSize(const BSize& size)
{
	member.size = size;
}
void BDisplay::setSize(int width, int height)
{
	member.size.set(width, height);
}
const BSize& BDisplay::size() const
{
	return member.size;
}

void BDisplay::setBackground(const BColor& background)
{
	member.bgColor = background;
}
const BColor& BDisplay::background() const
{
	return member.bgColor;
}

bool BDisplay::setWidget(BWidget* widget)
{
	if (member.widget != widget)
	{
		if (member.widget)
		{
			widget_member(member.widget)->display = 0;
			member.widget = 0;
			member.host = 0;
		}

		member.widget = widget;
		member.host = widget;

		if (member.widget)
		{
			widget_member(widget)->display = this;
			widget_member(widget)->window = 0;
			if (member.widget->parent() == 0)
			{

			}
		}
	}
	return true;
}
BWidget* BDisplay::widget() const
{
	return member.widget;
}

bool BDisplay::bind() const
{
	BTexture::bind();

	GLuint tbo = texture_member(this)->tbo;

	if (tbo == 0)
		return false;

	if (member.fbo == 0)
	{
		GLint backup_frame_buffer;
		glGetIntegerv(GL_FRAMEBUFFER_BINDING, &backup_frame_buffer);

		int width = member.size.width();
		int height = member.size.height();

		glGenFramebuffers(1, &member.fbo);
		if (!member.fbo)
			return false;

		glBindFramebuffer(GL_FRAMEBUFFER, member.fbo);
		{
			glGenRenderbuffers(1, &member.rbo_depth);
			glBindRenderbuffer(GL_RENDERBUFFER, member.rbo_depth);
			glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, member.rbo_depth);

			glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
			glBindTexture(GL_TEXTURE_2D, tbo);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tbo, 0);
		}
		glBindFramebuffer(GL_FRAMEBUFFER, backup_frame_buffer);
	}

	if (member.rbo_depth == 0)
		return false;

	GLint backup_frame_buffer;
	glGetIntegerv(GL_FRAMEBUFFER_BINDING, &backup_frame_buffer);
	glBindFramebuffer(GL_FRAMEBUFFER, member.fbo);
	{
		glDrawBuffer(GL_COLOR_ATTACHMENT0);
		member.update();
		member.fresh();
		member.frame();
	}
	glBindFramebuffer(GL_FRAMEBUFFER, backup_frame_buffer);

	glBindTexture(GL_TEXTURE_2D, tbo);

	member.check();

	return true;
}

void BDisplay::event(const BEvent& event)
{
	if (!member.widget)
		return;
	if (event.type() >= Event_MouseEnter && event.type() <= Event_DoubleClick)
	{
		BMouseEvent mouseEvent = (BMouseEvent&)event;
		mouseEvent.setAbsolutePos(mouseEvent.globalPos() - member.widget->pos());
		member.mouse_pos = mouseEvent.globalPos();
		if (event.type() == Event_MouseMove)
		{
			member.procMouseMove(mouseEvent);
		}
		if (event.type() == Event_MousePress)
		{
			member.procMousePress(mouseEvent);
		}
		if (event.type() == Event_MouseRelease)
		{
			member.procMouseRelease(mouseEvent);
		}

	}
	else
	{
		widget_member(member.widget)->procEvent(event);
	}
}
